#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Noah-predictor.h"
#include "predict_evaluation.h"

//这里进行noah完全随机访问测试，我们在一个普通的数据集下进行测试，看看noah的情况
//每一行的最大字节数，同时也是行缓冲区的大小
#define MAX_LINE_SIZE 1024

//所以我们一行行读出来，然后使用逗号分隔开
//将块大小设定为4K
#define PAGE_SIZE 4096

//noah预测深度的最大值
#define MAX_NOAH_PREDICT_DEEP 64



int main(){
    //使用一个新的数据集，我们使用src1_0。
    //首先从数据集中读取数据
    //从文件中一个个读入
    FILE *fp_read = NULL;
    char line[MAX_LINE_SIZE];
    long access_block;
    int access_size;

    //用来进行循环迭代的变量
    int i;
    int j;

    //记录总共多少行数据
    long record_count = 0;

    //这里记录顺序访问的数量
    long seq_access_count = 0;

    //这里记录noah被触发的数量
    long noah_active_count = 0;

    //总共访问的数据块数量
    long data_size = 0;

    //上一次访问的数据块记录
    long last_access_block = -1;
    int last_access_size = -1;

    //这里初始化一个预测序列，noah预测器和page预测器共用一个预测序列，因为二者不会被同时使用
    long* predict_seq;
    //预测的大小
    int size;
    //初始化一个预测序列
    predict_seq = (long*)malloc(MAX_NOAH_PREDICT_DEEP*sizeof(long));
    memset(predict_seq,0,MAX_NOAH_PREDICT_DEEP*sizeof(long));


    //初始化noah
    Noah_predictor_t noah;
    Noah_predictor_init(&noah, 1);

    //初始化一个评价器
    predict_evaluation_t predict_evaluation;
    init_predict_evaluation(&predict_evaluation);

    printf("开始运行预测\n");

    //将line中的数据分割为访问地址和访问大小，这里为分割做准备
    char delims[] = ",";
    char *result = NULL;

    if((fp_read = fopen("/Users/zhendu/study/OSChina/deep-IO-request-prediction/resource/MSR-Cambridge/mds_1.csv", "r"))!=NULL){
        printf("开始读取访问的历史记录，mds_1.csv\n");

        //开始遍历所有的访问序列
        while(fgets(line, MAX_LINE_SIZE, fp_read)){
            //首先判断当前是读还是写，写直接跳过
            if(strstr(line, "Write") != NULL){
                continue;
            }

            //将每一行内容读入
            record_count++;

            if(record_count % 10000 == 0){
                printf("正在读取第%ld个数据\n", record_count);
            }

            //这里是个分割的元素
            result = strtok( line, delims );

            //这里要进行计数，只保留第5列
            i = 1;

            //记录历史的访问块号
            last_access_block = access_block;
            last_access_size = access_size;

            //这里遍历一整行得到对应的访问的块号和size
            while((result = strtok( NULL, delims))){
                i++;

                if(i == 5){
                    access_block = atol(result);

                    //将字符串换成数字
                    access_block = access_block / PAGE_SIZE;

                    // first_offset = atol(result) % PAGE_SIZE;
                    // printf("%ld,", access_block);
                }
                //这里将offset也考虑在内
                if(i == 6){
                    //看看结束的数字
                    access_size = atol(result);
                    access_size = access_size / PAGE_SIZE;

                    // printf("%ld\n", access_size);
                }
            }

            data_size = access_size + data_size;

            // printf("%ld,%d\n", access_block,access_size);
            for(i = 0; i < access_size; i++){
                //将数据按照4k拆开，然后分开更新数据
                noah_predictor(&noah, access_block+i, predict_seq, &size);

                //更新预测结果评价统计
                update_predict_evaluation(&predict_evaluation, access_block+i);
            }

            //如果noah在这一轮中没有触发，那么触发real_page_update
            if(size != 0){
                noah_active_count++;
                // printf("noah预读结果:");
                // //查看获取的预读结果
                // for(i = 0; i < size; i++){
                //     printf("%ld,",predict_seq[i]);
                // }
                // printf("\n");
            }

            //将预测结果写入新的评判器
            for(i = 0; i < size; i++){
                insert_predict_history(&predict_evaluation, predict_seq[i]);
            }

            //提前截止
            if(record_count  == 500000){
                break;
            }
        }
    }else{
        printf("文件开启失败\n");
        return 0;
    }

    //这里打印总共弹出的数量和错误的数量以及预测触发的数量，以及顺序访问的数量s
    printf("弹出历史记录的数量：%ld\n", predict_evaluation.history_count);
    printf("错误预测的数量：%ld\n", predict_evaluation.err_count);
    printf("noah触发的数量：%ld\n", noah_active_count);
    printf("总访问数据块的数量：%ld\n", data_size);

    //关闭
    printf("总共读取的历史记录个数：%ld\n",record_count);
    fclose(fp_read);
    fp_read = NULL;

    return 0;
}